home *** CD-ROM | disk | FTP | other *** search
- /** compile.c
- ** Main compilation routines.
- **
- ** Written by and Copyright 1994 Asher Hoskins.
- **
- ** The author retains copyright on this implementation. Permission for
- ** educational and non-profit use is granted to all. If you're planning to
- ** make money with this or any code derived from it, check with the author
- ** first.
- **/
-
- #include <stdio.h>
- #include "compile.h"
- #include "parse.h"
-
- static token_val_t err_get_token(char *, int *, int);
- static char *err_trans(int);
- static void compile_statement(char *, int *, FILE *, int);
- static void show_err(char *, int);
- static void needs_token(token_t, char *, int *, int);
- static int isrelop(token_t);
- static int isexprarg(token_t);
- static int isexprop(token_t);
- static char *expr_arg(token_val_t);
- static void assignment(token_val_t, char *, int *, FILE *, int);
-
- /** Output stuff before main code.
- **/
-
- void start_compile(FILE *out, int argc, char *argv[])
- {
- fputs("/* Compiled by kvik */\n", out);
- fputs("#include \"kvik_obj_header.h\"\n", out);
- if (argc > 2)
- fprintf(out, "#include \"%s\"\n", argv[2]);
- }
-
- /** Output stuff after main code.
- **/
-
- void end_compile(FILE *out)
- {
- fputs("#include \"kvik_obj_tail.h\"\n", out);
- fputs("/* end */\n", out);
- }
-
- /** Compile a line.
- **/
-
- void compile_line(char *line, FILE *out, int linenum)
- {
- token_val_t t;
- int offset = 0;
-
- compile_statement(line, &offset, out, linenum);
- t = err_get_token(line, &offset, linenum);
- if (t.token != T_NEWLINE) {
- fprintf(stderr, "kvik: Too much in line %d.\n", linenum);
- exit(1);
- }
- }
-
- /** Compile one statement.
- **/
-
- static void compile_statement(char *line, int *offset, FILE *out, int linenum)
- {
- token_val_t t, tstore;
- char digit;
-
- t = err_get_token(line, offset, linenum);
- switch (t.token) {
-
- case T_NEWLINE:
- return;
-
- case T_PROGRAM_POINTER_DEF:
- fprintf(out, "case %s:\n", t.val.label);
- return;
-
- case T_PROG_POINTER_STORE_DEF: case T_DATA_POINTER_DEF:
- tstore = t;
- t = err_get_token(line, offset, linenum);
- if (t.token == T_BIGNUM) {
- fprintf(out, "alloc_storage(%s, %d, %d);\n", tstore.val.label,
- t.val.num, (tstore.token==T_DATA_POINTER_DEF)?0:-3);
- return;
- }
- break;
-
- case T_POINTS_TO:
- t = err_get_token(line, offset, linenum);
- if (t.token == T_PROGRAM_POINTER) {
- fprintf(out, "gd = p[%d]; break;\n", t.val.digit);
- return;
- }
- break;
-
- case T_PROGRAM_POINTER:
- digit = t.val.digit;
- t = err_get_token(line, offset, linenum);
- switch (t.token) {
- case T_POINTS_TO:
- t = err_get_token(line, offset, linenum);
- if (t.token == T_BIGNUM) {
- fprintf(out, "p[%d] = %d;\n", digit, t.val.num);
- return;
- }
- case T_ASSIGN:
- t = err_get_token(line, offset, linenum);
- if (t.token == T_DATA_POINTER) {
- fprintf(out, "p[%d] = read_data(&d[%d]);\n", digit,
- t.val.digit);
- return;
- }
- }
- break;
-
- case T_REGISTER: case T_DATA_POINTER: case T_CHANNEL: case T_NUMBER:
- case T_CONSTANT:
- tstore = t;
- t = err_get_token(line, offset, linenum);
- switch (t.token) {
-
- case T_PREVIOUS:
- fprintf(out, "previous(&d[%d]);\n", tstore.val.digit);
- return;
-
- case T_NEXT:
- fprintf(out, "next(&d[%d]);\n", tstore.val.digit);
- return;
-
- case T_POINTS_TO:
- t = err_get_token(line, offset, linenum);
- fprintf(out, "set_dp(&d[%d], %d, ", tstore.val.digit, t.val.num);
- t = err_get_token(line, offset, linenum);
- switch (t.token) {
- case T_NEWLINE:
- fputs("0);\n", out);
- return;
- case T_NUMBER:
- fprintf(out, "%d);\n", t.val.num);
- return;
- case T_REGISTER:
- fprintf(out, "r[%d]);\n", t.val.digit);
- return;
- case T_DATA_POINTER:
- fprintf(out, "read_data(&d[%d]));\n", digit);
- return;
- }
- break;
-
- case T_ASSIGN:
- assignment(tstore, line, offset, out, linenum);
- return;
-
- default:
- if (isrelop(t.token)) {
- fprintf(out, "if (expr(1, %s, %d, ", expr_arg(tstore),
- t.token);
- t = err_get_token(line, offset, linenum);
- if (isexprarg(t.token)) {
- fprintf(out, "1, %s)) {\n", expr_arg(t));
- needs_token(T_POINTS_TO, line, offset, linenum);
- t = err_get_token(line, offset, linenum);
- if (t.token == T_PROGRAM_POINTER) {
- fprintf(out, " gd = p[%d]; break;\n}\n", t.val.digit);
- return;
- }
- }
- }
- }
- }
-
- fprintf(stderr, "kvik: Syntax error in line %d:\n", linenum);
- show_err(line, *offset);
- exit(1);
- }
-
- /** Read a token, exiting if there's an error.
- **/
-
- static token_val_t err_get_token(char *line, int *offset, int linenum)
- {
- token_val_t ret;
-
- ret = get_token(line, offset);
- if (ret.token != T_ERROR)
- return(ret);
-
- fprintf(stderr, "kvik: %s in line %d:\n", err_trans(ret.val.errnum),
- linenum);
- show_err(line, *offset);
- exit(1);
- }
-
- /** Translate an error number into text.
- **/
-
- static char *err_trans(int errnum)
- {
- switch(errnum) {
- case PE_TRUNC:
- return("Line too long");
- case PE_BADNUM:
- return("Bad number");
- case PE_BADTOK:
- return("Unknown token");
- case PE_BADDIGIT:
- return("Bad digit");
- }
-
- return("Error");
- }
-
- /** Show where in a line an error occurred.
- **/
-
- static void show_err(char *line, int offset)
- {
- int i;
-
- fputs(line, stderr);
- for (i=0; i<offset; i++)
- putc('-', stderr);
- fputs("^\n", stderr);
- }
-
- /** Exit if the next token is not 'tok'.
- **/
-
- static void needs_token(token_t tok, char *line, int *offset, int linenum)
- {
- token_val_t t;
-
- t = err_get_token(line, offset, linenum);
- if (t.token != tok) {
- fprintf(stderr, "kvik: Unexpected token in line %d:\n", linenum);
- show_err(line, *offset);
- exit(1);
- }
- }
-
- /** Return 1 if 'tok' is a relational operator.
- **/
-
- static int isrelop(token_t tok)
- {
- return(tok==T_EQUAL || tok==T_NOT_EQUAL || tok==T_LESS_THAN ||
- tok==T_GREATER_THAN || tok==T_LESS_THAN_OR_EQ ||
- tok==T_GREATER_THAN_OR_EQ);
- }
-
- /** Return 1 if 'tok' is a valid expression argument.
- **/
-
- static int isexprarg(token_t tok)
- {
- return(tok==T_REGISTER || tok==T_DATA_POINTER || tok==T_CHANNEL ||
- tok==T_NUMBER || tok==T_CONSTANT);
- }
-
- /** Return 1 if 'tok' is a valid expression operator.
- **/
-
- static int isexprop(token_t tok)
- {
- return(isrelop(tok) || tok==T_PLUS || tok==T_MINUS || tok==T_MULTIPLY ||
- tok==T_DIVIDE);
- }
-
- /** Convert a token into something suitable for passing to the expr function.
- **/
-
- static char *expr_arg(token_val_t t)
- {
- static char ret[30];
-
- switch (t.token) {
- case T_REGISTER:
- sprintf(ret, "r[%d]", t.val.digit);
- break;
- case T_DATA_POINTER:
- sprintf(ret, "read_data(&d[%d])", t.val.digit);
- break;
- case T_CHANNEL:
- sprintf(ret, "read_channel(%d)", t.val.digit);
- break;
- case T_NUMBER:
- sprintf(ret, "%d", t.val.num);
- break;
- case T_CONSTANT:
- sprintf(ret, "CONST%d", t.val.digit);
- }
-
- return(ret);
- }
-
- /** Handle assignment statements.
- **/
-
- static void assignment(token_val_t tstore, char *line, int *offset, FILE *out,
- int linenum)
- {
- token_val_t t;
- int neg = 1;
-
- t = err_get_token(line, offset, linenum);
- if (t.token == T_PROGRAM_POINTER)
- if (tstore.token == T_DATA_POINTER) {
- fprintf(out, "write_data(&d[%d], p[%d]);\n", tstore.val.digit,
- t.val.digit);
- return;
- }
- else {
- fprintf(stderr, "kvik: Expected program pointer in line %d:\n",
- linenum);
- show_err(line, *offset);
- exit(1);
- }
-
- switch (tstore.token) {
-
- case T_NUMBER: case T_CONSTANT:
- fprintf(stderr, "kvik: Can't assign to a number/const in line %d:\n",
- linenum);
- show_err(line, 0);
- exit(1);
-
- case T_REGISTER:
- fprintf(out, "r[%d] = ", tstore.val.digit);
- break;
-
- case T_DATA_POINTER:
- fprintf(out, "write_data(&d[%d], ", tstore.val.digit);
- break;
-
- case T_CHANNEL:
- fprintf(out, "write_channel(%d, ", tstore.val.digit);
- }
-
- if (t.token == T_UMINUS) {
- neg = -1;
- t = err_get_token(line, offset, linenum);
- }
-
- if (isexprarg(t.token)) {
- fprintf(out, "expr(%d, %s, ", neg, expr_arg(t));
- t = err_get_token(line, offset, linenum);
- if (isexprop(t.token)) {
- fprintf(out, "%d, ", t.token);
- t = err_get_token(line, offset, linenum);
- if (t.token == T_UMINUS) {
- neg = -1;
- t = err_get_token(line, offset, linenum);
- }
- else
- neg = 1;
- if (isexprarg(t.token))
- fprintf(out, "%d, %s)", neg, expr_arg(t));
- else {
- fprintf(stderr, "kvik: Illegal expression in line %d:\n",
- linenum);
- show_err(line, *offset);
- exit(1);
- }
- }
- else if (t.token == T_NEWLINE)
- fprintf(out, "%d, 1, 0)", T_PLUS);
- else {
- fprintf(stderr, "kvik: Expected an operator in line %d:\n",
- linenum);
- show_err(line, *offset);
- exit(1);
- }
- }
- else {
- fprintf(stderr, "kvik: Illegal expression in line %d:\n", linenum);
- show_err(line, *offset);
- exit(1);
- }
-
- if (tstore.token == T_REGISTER)
- fputs(";\n", out);
- else
- fputs(");\n", out);
-
- return;
- }
-
-